#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <signal.h>
#include <fusbpush_ioctl.h>


#define CHUNK_SIZE 1000

unsigned int addr = 0x30000000;

void print_help(void);
unsigned short chksum(unsigned char *prog, unsigned int sizeOfBinFile);
void sigint_sighandler(int sig);

unsigned int sizeOfBinFile = 0; 
int fd = 0;
int fdBinFile = 0;
unsigned char *prog = NULL, *buf = NULL;

void sigint_handler(int sig)
{
    printf("\nCtrl+C Captured");
    //Call the ioctl
    if(fd)    
    {
        if(ioctl(fd, IOCTL_STOP_TRANSACTION, 0))
            printf("\n ERROR in sending IOCTL call - IOCTL_STOP_TRANSACTION");
	else
	    printf("\n Successfully sent IOCTL command to myusbpush driveri\n\n");	
        close(fd);
    }

	       
    if(buf)
        free(buf);
    if(prog)    
        munmap(prog, sizeOfBinFile);
    if(fdBinFile)        
        close(fdBinFile);            
    
    exit(1);    
        
}

int main(int argc, char *argv[])
{
    unsigned char *cur = NULL;
    unsigned int noOfBytesRead = 0, noOfBytesWritten = 0;
    unsigned char tempBuff[10];
    unsigned short checkSum = 0;
    unsigned int count = 0;
    unsigned int tot_len = 0;
    unsigned int remain;
    struct sigaction sa;
    struct stat fstat;
    int status = 0;

    /* Check whether user has typed correct args */
    if(argc != 2 )
    {
        print_help();
    }
    else
    {
    
        sa.sa_handler = sigint_handler;
        sa.sa_flags = 0;
        sigemptyset(&sa.sa_mask);
        
        if (sigaction(SIGINT, &sa, NULL) == -1) 
        {
            perror("sigaction");
            exit(1);
        }
        
          
        /* 
            argc 2 should be - Memory of mini2440
            argc 3 should be - Path of the Binary file to be flashed
        */
        if(stat(argv[argc-1], &fstat))
        {
            printf("\n Unable to get file statistics");
            exit(1);
        }
        else
        {
            sizeOfBinFile = (unsigned int)fstat.st_size;
            printf("\n Size of the file in bytes is:%d", sizeOfBinFile);
        }
    }
    
    fdBinFile = open(argv[argc-1], O_RDONLY);
    if(fdBinFile<0)
    {
        printf("\n Unable to open :%s", argv[argc-1]);
        close(fd);
        exit(1);
    }
    
    /* TODO - Need to break this down into multiple calls based on the
    size of the binary image */
   	prog = mmap(NULL, sizeOfBinFile, PROT_READ, MAP_SHARED, \
   	    fdBinFile, 0);
	if (!prog)
	{
	    close(fdBinFile);
		exit(1);
	}

    checkSum = chksum(prog, sizeOfBinFile);
    printf("\nCheckSum is:%d", checkSum);

    fd = open("/dev/fusbpushDev", O_WRONLY);
    if(fd<0)
    {
        printf("\n Unable to open the device node");
        exit(1);
    }

    tot_len = sizeOfBinFile+ 10;
    buf = malloc(tot_len);
    if(!buf)
        printf("\nError in allocating buffer");
    else
    {
        /* Add RAM Address */
	    buf[0] = addr & 0xff;
	    buf[1] = (addr >> 8) & 0xff;
	    buf[2] = (addr >> 16) & 0xff;
	    buf[3] = (addr >> 24) & 0xff;

        /* Add Length of the binary file */
	    buf[4] = tot_len & 0xff;
	    buf[5] = (tot_len >> 8) & 0xff;
	    buf[6] = (tot_len >> 16) & 0xff;
	    buf[7] = (tot_len >> 24) & 0xff;
	    
	    /* Copy the binary data */
	    memcpy(buf+8, prog, sizeOfBinFile);

        /* Add the checksum */
	    buf[sizeOfBinFile+8] = checkSum & 0xff;
	    buf[sizeOfBinFile+9] = (checkSum >> 8) & 0xff;

	    printf("send_file: addr = 0x%08x, len = 0x%08x\n", \
	        addr, sizeOfBinFile);
		
	    for (cur = buf; cur < buf+tot_len; cur += CHUNK_SIZE) 
	    {
		    remain = (buf + tot_len) - cur;
		    if (remain > CHUNK_SIZE)
			    remain = CHUNK_SIZE;

		    noOfBytesWritten = write(fd, cur, remain);
		    if (noOfBytesWritten < 0)
		    {
		        printf("\nError in writing data to USB");
                munmap(prog, sizeOfBinFile);
                close(fdBinFile);            
                close(fd);
                free(buf);
                exit(1);
		    }
		    printf("#");
	    }
    
    printf("\n Successfully written data");
    printf("\n");

	free(buf);
           
    }    
    
    
    munmap(prog, sizeOfBinFile);
    close(fdBinFile);            
    close(fd);
}

void print_help(void)
{
    printf("\n Usage - testApp <Path of the binary file> \n \
    Example: testApp /home/souvik/test.bin \n \
    NOTE: Default memory address is : 0x3000 0000");
    printf("\n");
    exit(1);    
}

unsigned short chksum(unsigned char *prog, unsigned int sizeOfBinFile)
{
    unsigned short checksum = 0;
    unsigned char buff;
    unsigned int count = 0;
    for(;count < sizeOfBinFile; count++)
        checksum += prog[count];
    
    return checksum;        
}


